package com.sxhuayuan.parking.plugin.invoice.nuonuo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sxhuayuan.parking.config.InvoiceStatus;
import com.sxhuayuan.parking.entity.*;
import com.sxhuayuan.parking.exception.SystemException;
import com.sxhuayuan.parking.plugin.invoice.InvoicePlugin;
import com.sxhuayuan.parking.plugin.invoice.nuonuo.dto.Detail;
import com.sxhuayuan.parking.plugin.invoice.nuonuo.dto.InvoiceInfoDto;
import com.sxhuayuan.parking.plugin.invoice.nuonuo.request.QueryInvoiceRequest;
import com.sxhuayuan.parking.service.InvoiceService;
import com.sxhuayuan.parking.service.ParkingLotService;
import com.sxhuayuan.parking.utils.DESUtils;
import com.sxhuayuan.parking.utils.DateUtils;
import com.sxhuayuan.parking.utils.SettingUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
 * 诺诺发票系统插件
 * 
 * @author helong
 * @create 2019/8/30 10:00
 */
@Slf4j
@Component(NuonuoInvoicePlugin.ID)
public class NuonuoInvoicePlugin extends InvoicePlugin {
	@Resource(name = "invoiceServiceImpl")
	InvoiceService service;
	@Resource(name = "parkingLotServiceImpl")
	ParkingLotService parkingLotService;

	public static final String ID = "nuonuoInvoicePlugin";

	/**
	 * 税号：339901999999142 六位极速开票代码：DND3E7 appsecret：12345678abcdefgh
	 */

	@Override
	public String getId() {
		return NuonuoInvoicePlugin.ID;
	}

	@Override
	public String getName() {
		return "诺诺网发票";
	}

	@Override
	public String getQrCodeUrl() {
		return "/invoice/scan/k.action";
	}

	@Override
	public String getSiteUrl() {
		if (SettingUtils.get().getIsDebug()) {
			return "https://nnfpbox.nuonuocs.cn";
		} else {
			return "https://nnfp.jss.com.cn";
		}
	}

	@Override
	public String getQueryInvoiceStateUrl() {
		return "/shop/buyer/allow/ecOd/queryElectricKp.action";
	}

	@Override
	public String getInvoiceQrCode(Invoice invoice, ParkingLot parkingLot) throws SystemException {
		InvoiceSetting invoiceSetting = parkingLot.getInvoiceSetting();
		if (invoiceSetting == null) {
			throw new SystemException("发票系统未配置");
		}
		String userName = invoiceSetting.getUserName();
		String encrySn = getEncryptionInvoiceSn(invoice.getSn(), invoiceSetting.getSecretKey());
		return getSiteUrl() + getQrCodeUrl() + "?j=" + userName + ":" + encrySn;
	}

	@Override
	public void invoiceCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 接口标识
		String operater = request.getParameter("operater");
		// queryInfoByOrderId 表示根据订单id 获取开票信息
		if ("queryInfoByOrderId".equals(operater)) {
			getOrderInfo(request, response);
		} else if ("invoiceApply".equals(operater)) {// 接口标识 invoiceApply 为开票申请回调
			invoiceApplycallback(request, response);
		} else if ("callback".equals(operater)) {// 开票结果回调
			callback(request, response);
		}
	}

	@Override
	public boolean queryInvoiceState(Invoice invoice) {
		try {
			ParkingLot parkingLot = parkingLotService.findOne(invoice.getParkingLotId());
			InvoiceSetting invoiceSetting = parkingLot.getInvoiceSetting();
			QueryInvoiceRequest request = new QueryInvoiceRequest(invoiceSetting.getNuonuoIdentity(), invoice.getSn());
			Map<String, Object> mapParameter = request.getMapParameter();
			String post = post(getSiteUrl() + getQueryInvoiceStateUrl(), mapParameter);
			JSONObject obj = JSON.parseObject(post);
			String result = obj.getString("result");
			if ("success".equals(result)) {
				JSONObject object = obj.getJSONArray("list").getJSONObject(0);
				if ("2".equals(object.getString("c_status"))) {
					invoiceSuccess(invoice, object);
				} else {
					invoice.setStatus(InvoiceStatus.fail);
					Set<Order> orders = new HashSet<>();
					for (Order order : invoice.getOrders()) {
						order.setInvoiceStatus(InvoiceStatus.fail);
						orders.add(order);
					}
					invoice.setOrders(orders);
					service.update(invoice);
				}
				return true;
			}
		} catch (Exception e) {
			return false;
		}
		return false;
	}

	/** 开票结果回调 */
	private void callback(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String orderno = request.getParameter("orderno");
		log.debug("【{}】开票结果回调", orderno);
		Invoice invoice = service.findBySn(orderno);
		if (invoice == null) {
			log.debug("【{}】发票记录不存在", orderno);
			returnStr(response, "{\"status\":\"9999\",\"message\":\"发票记录不存在\"}");
			return;
		} else if (invoice.getStatus() == InvoiceStatus.success) {
			log.debug("【{}】发票已经开过", orderno);
			returnStr(response, "{\"status\":\"9999\",\"message\":\"发票已经开过\"}");
			return;
		}
		String content = request.getParameter("content");
		JSONObject obj = JSON.parseObject(content);
		log.debug("【{}】回调内容:{}", orderno, obj.toJSONString());
		invoiceSuccess(invoice, obj);
		returnStr(response, "{\"status\":\"0000\",\"message\":\"同步成功\"}");
	}

	/** 诺诺网获取订单详情 */
	private void getOrderInfo(HttpServletRequest request, HttpServletResponse response) throws IOException {
		String orderno = request.getParameter("orderno");
		log.debug("【{}】查询开票信息", orderno);
		Invoice invoice = service.findBySn(orderno);
		if (invoice == null) {
			log.debug("【{}】发票记录不存在", orderno);
			returnStr(response, "{\"status\":\"9999\",\"message\":\"发票记录不存在\"}");
			return;
		} else if (invoice.getStatus() == InvoiceStatus.success) {
			log.debug("【{}】发票已开具成功", orderno);
			returnStr(response, "{\"status\":\"9999\",\"message\":\"发票已经开过\"}");
			return;
		}
		Member member = invoice.getMember();
		ParkingLot parkingLot = parkingLotService.findOne(invoice.getParkingLotId());
		if (parkingLot == null || member == null || parkingLot.getInvoiceSetting() == null) {
			returnStr(response, "{\"status\":\"9999\",\"message\":\"车场不存在或发票设置有误\"}");
			return;
		}
		InvoiceSetting invoiceSetting = parkingLot.getInvoiceSetting();
		InvoiceTitle invoiceTitle = member.getInvoiceTitle();
		InvoiceInfoDto invoiceInfo = new InvoiceInfoDto();
		invoiceInfo.setOrderno(orderno);
		invoiceInfo.setOrdertotal(invoice.getOrdertotal().toString());
		invoiceInfo.setTaxtotal(invoice.getTaxAmount().toString());
		invoiceInfo.setBhtaxtotal(invoice.getTaxFreeAmount().toString());
		if (invoiceTitle == null) {
			invoiceInfo.setTsfs("-1");
			invoiceInfo.setSelfFlag("0");
		} else {
			invoiceInfo.setSelfFlag("1");
			if (invoiceTitle.getEmail() == null && invoiceTitle.getPhone() == null) {
				invoiceInfo.setTsfs("-1");
			} else if (StringUtils.isNotEmpty(invoiceTitle.getEmail()) && invoiceTitle.getPhone() == null) {
				invoiceInfo.setTsfs("0");
				invoiceInfo.setEmail(invoiceTitle.getEmail());
			} else if (StringUtils.isNotEmpty(invoiceTitle.getPhone()) && invoiceTitle.getEmail() == null) {
				invoiceInfo.setTsfs("1");
				invoiceInfo.setPhone(invoiceTitle.getPhone());
			} else if (StringUtils.isNotEmpty(invoiceTitle.getEmail()) && StringUtils.isNotEmpty(invoiceTitle.getPhone())) {
				invoiceInfo.setTsfs("2");
				invoiceInfo.setEmail(invoiceTitle.getEmail());
				invoiceInfo.setPhone(invoiceTitle.getPhone());
			}
			invoiceInfo.setTaxnum(invoiceTitle.getTaxnum());
			invoiceInfo.setBuyername(invoiceTitle.getName());
			invoiceInfo.setAddress(invoiceTitle.getAddress());
			invoiceInfo.setAccount(invoiceTitle.getAccount());
		}

		invoiceInfo.setInvoicedate(DateUtils.format(invoice.getInvoiceTime()));
		invoiceInfo.setMessage("");
		invoiceInfo.setClerk(invoiceSetting.getClerk());
		invoiceInfo.setPayee(invoiceSetting.getPayee());
		invoiceInfo.setChecker(invoiceSetting.getChecker());
		invoiceInfo.setBuyername(invoiceSetting.getName());
		invoiceInfo.setSaleaddress(invoiceSetting.getAddress());
		invoiceInfo.setSalephone(invoiceSetting.getPhone());
		invoiceInfo.setSaleaccount(invoiceSetting.getBankAccount());
		Detail detail = new Detail();
		detail.setGoodsname("停车缴费");
		detail.setPrice(invoice.getOrdertotal().toString());
		detail.setTaxrate(invoiceSetting.getTaxRate().toString());
		detail.setSpbm(invoiceSetting.getTaxTypeCode());
		detail.setTaxfreeamt(invoice.getOrdertotal().toString());
		detail.setTax(invoice.getTaxAmount().toString());
		detail.setTaxfreeamt(invoice.getTaxFreeAmount().toString());
		List<Detail> list = new ArrayList<>();
		list.add(detail);
		invoiceInfo.setDetail(list);
		String jsonString = JSON.toJSONString(invoiceInfo);
		log.debug("【{}】返回开票详情:{}", orderno, jsonString);
		returnStr(response, jsonString);
	}

	/** 诺诺网发票开票申请回调 */
	private void invoiceApplycallback(HttpServletRequest request, HttpServletResponse response) throws IOException {
		String orderno = request.getParameter("orderno");
		log.debug("【{}】开票申请回调", orderno);
		Invoice invoice = service.findBySn(orderno);
		if (invoice == null) {
			returnStr(response, "{\"tipMsg\":\"发票记录不存在\"}");
			return;
		}
		String isSuccess = request.getParameter("isSuccess");
		if (!"true".equals(isSuccess)) {
			log.debug("【{}】开票申请失败", orderno);
			invoice.setStatus(InvoiceStatus.fail);
			service.update(invoice);
			returnStr(response, "{\"status\":\"9999\",\"message\":\"开票申请失败\"}");
		} else {
			log.debug("【{}】开票申请成功", orderno);
			returnStr(response, "{\"status\":\"0000\",\"message\":\"同步成功\"}");
		}
	}

	private void invoiceSuccess(@NotNull Invoice invoice, @NotNull JSONObject obj) {
		invoice.setInvoiceCode(obj.getString("c_fpdm"));
		invoice.setInvoiceNum(obj.getString("c_fphm"));
		invoice.setFileUrl(obj.getString("c_url"));
		invoice.setExternalSn(obj.getString("c_fpqqlsh"));
		invoice.setImgUrl(obj.getString("c_jpg_url "));
		invoice.setCheckCode(obj.getString("checkCode"));
		// invoice.setQrCode(obj.getString("qrCode"));
		invoice.setMachineCode(obj.getString("machineCode"));
		invoice.setCipherText(obj.getString("cipherText"));
		invoice.setStatus(InvoiceStatus.success);
		Set<Order> orders = new HashSet<>();
		for (Order order : invoice.getOrders()) {
			order.setInvoiceStatus(InvoiceStatus.success);
			orders.add(order);
		}
		invoice.setOrders(orders);
		service.update(invoice);
	}

	/** 接口返回加密结果 */
	private void returnStr(HttpServletResponse response, String str) throws IOException {
		response.setCharacterEncoding("UTF-8");
		PrintWriter writer = response.getWriter();
		writer.print(DESDZFP.encrypt(str));
		writer.flush();
		writer.close();
	}

	/**
	 * 获取加密的发票流水号<br/>
	 * 截取流水号后面一部分进行des加密，前半部分与加密后半部分用 ：连接
	 * 
	 * @param sn
	 *            原发票流水号
	 * @param secretKey
	 *            加密秘钥
	 * @return 加密后的流水号
	 */
	private String getEncryptionInvoiceSn(String sn, String secretKey) throws SystemException {
		if (sn.length() <= 10) {
			throw new SystemException("订单号低于10位");
		}
		if (secretKey == null || secretKey.length() < 16) {
			throw new SystemException("秘钥有误");
		}
		// 获取4-8的随机数
		int randomNumber = (int) (4 + Math.random() * (8 - 1 + 1));
		String front = sn.substring(0, sn.length() - randomNumber);
		String tail = sn.substring(sn.length() - randomNumber);
		try {
			String decrypt = DESUtils.encrypt(tail, secretKey.substring(0, 8), secretKey.substring(secretKey.length() - 8));
			String s = front + ":" + decrypt;
			log.debug("加密前流水号：{}\n加密后流水号：{}", sn, s);
			return s;
		} catch (Exception e) {
			throw new SystemException(e.getMessage());
		}
	}

}
